#lang racket
(require rackunit)

(define-syntax-rule (ADD x y)
  (+ x y))

(check-equal? (* (ADD 1 2) 3) (* (+ 1 2) 3))
#|
(define-syntax-rule (SQR x)
  (* x x))
|#

(define-syntax-rule (SQR x)
  ((lambda (new-x) (* new-x new-x))
   x))



(check-equal?
  (SQR (* 2 3))
  (* (* 2 3) (* 2 3))) ; expands x twice!

(define (f)
  (display "!\n")
  3)

; (SQR 3)
(SQR (f))
#|
(check-equal?
  (SQR (f))
  (* (f) (f))) ; expands x twice!
; ! ! 9
|#

(define-syntax-rule (IF cnd then-branch else-branch)
  (or (and cnd then-branch) else-branch))

#|
(define (IF cnd then-branch else-branch)
  (or (and cnd then-branch) else-branch))
|#
; Sanity tests; in case of eager evaluation it should crash
(check-equal? (IF #t 1 (/ 1 0)) 1)
(check-equal? (IF #f (/ 1 0) 2) 2)
#|
(define (assert x)
  (IF x (void) (error "Condition failed: " x)))
|#

(define-syntax-rule (assert x)
  (IF x (void) (error "Condition failed: " (quote x))))


;(assert (and #f 10))


(define-syntax-rule (letin x v e)
  ((lambda (x) e) v))

(check-equal? (letin x (+ 10 50) x) 60)

(require syntax/parse/define)
#|
(define-simple-macro (fn x:id body:expr)
  (lambda (x) body))
|#
#|
(check-equal?
  ((fn x x) 10)
  ((lambda (x) x) 10))
|#
(define-simple-macro (fn x:id (~literal ->) expr:expr)
  (lambda (x) expr))

;(lambda (1) 10)

((fn x -> 10) 99) ; (lambda (x) x)


(do x <- o ...)
#|
(define (enviornment-get m e x) ...)

(define (env-get e x)
  (lambda (m)
    ; call environment-get here
  ))
|#
#|
; Existing version
(define (d:eval-exp mem env exp)
  ...)
; What is being asked in HW7
(define (d:eval-exp env exp)
  (lambda (mem)
    ...))
; What is being asked in HW7 with the do-notation
|#
#|
; Before do-notation
(define (d:eval-exp meme env exp)
  (define v1+mem1 (d:eval-exp mem env e1))
  (define mem1 (eff-state v1+mem1))
  (define v1 (eff-result v1+mem1))
  ;; E' <- E + [x := v1]
  (define env2+mem2 (environ-push mem1 env y v1))
  (define env2 (eff-result env2+mem2))
  (define mem2 (eff-state env2+mem2))
  ;; e2 ⇓E' v2
  (define v2+mem3 (d:eval-exp mem2 env2 e2))
  (define mem3 (eff-state v+mem1))
  (define v2 (eff-result v+mem1))
  v2+mem3)
; After do-notation translation
(define (d:eval-exp env exp)
  (do
    ;; e1 ⇓E v1
    v1 <- (d:eval-exp env e1)
    ;; E' <- E + [x := v1]
    env2 <- (env-push env y v1)
    ;; e2 ⇓E' v2
    v2 <- (d:eval-exp env2 e2)
    (pure v2)
))
|#


;(do x <- .. y <- ... ....... )














;